package com.harmay.center.monitor.utils;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;

/**
 * @author Zuper
 * @date 2022/2/22 17:50
 */
@Slf4j
public class JsonUtils {

    public static ObjectMapper jackson() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, IOException {
                jsonGenerator.writeString("");
            }
        });
        objectMapper// 设置允许序列化空的实体类（否则会抛出异常）
                .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
                // 设置 把java.util.Date, Calendar输出为数字（时间戳）
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                // 设置在遇到未知属性的时候不抛出异常
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                // 强制JSON 空字符串("")转换为null对象值
                .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)
                // 设置数字丢失精度问题
                .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
                // 设置没有引号的字段名
                .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
                // 设置允许单引号
                .enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES)
                // 设置DateFormat格式化格式
                .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
                // 设置接受只有一个元素的数组的反序列化
                .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
                //按字母顺序排序属性,默认false
                .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
                //序列化Map时对key进行排序操作，默认false
                .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
        return objectMapper;
    }

    public static ObjectMapper jacksonWithType() {
        ObjectMapper objectMapper = jackson();
        objectMapper.enableDefaultTyping();
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        return objectMapper;
    }

    public static ObjectMapper jacksonWithFieldAccessable() {
        ObjectMapper objectMapper = jacksonWithType();
        objectMapper.setVisibilityChecker(objectMapper.getSerializationConfig().getDefaultVisibilityChecker()
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY).withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withSetterVisibility(JsonAutoDetect.Visibility.NONE).withCreatorVisibility(JsonAutoDetect.Visibility.ANY));
        return objectMapper;
    }

    public static <T> T trySelect(String json, String selector) {
        try {
            return JsonPath.read(json, selector);
        } catch (PathNotFoundException e) {
            return null;
        }
    }

    public static <T> T trySelectFirstNonNull(String json, String... selectors) {
        try {
            DocumentContext dc = JsonPath.parse(json);
            for (String selector : selectors) {
                try {
                    return dc.read(selector);
                } catch (PathNotFoundException e) {
                }
            }
        } catch (Exception e) {
            log.error("", e);
        }
        return null;
    }

    public static <T> T select(String json, String selector) {
        return JsonPath.read(json, selector);
    }

    /**
     * 将object转json字符串
     *
     * @param object
     * @return
     * @throws JsonProcessingException
     */
    public static String toJSONString(Object object) throws JsonProcessingException {
        return jackson().writeValueAsString(object);
    }

    /**
     * 将object转json字符串
     *
     * @param object
     * @return
     * @throws JsonProcessingException
     */
    public static String toJSONStringOrNull(Object object) {
        try {
            return jackson().writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.error("json转换失败", e);
        }
        return null;
    }

    /**
     * 将json串反序列化成Object
     *
     * @param json
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T parseObject(String json, Class<T> clazz) {
        if (StringUtils.isBlank(json) || clazz == null) {
            return null;
        }

        try {
            return clazz.equals(String.class) ? (T) json : jackson().readValue(json, clazz);
        } catch (Exception e) {
            log.warn("json To obj is error", e);
            return null;
        }
    }


    /**
     * 通过   TypeReference    处理List<User>这类多泛型问题,示例:new TypeReference<List<User>>(){}
     *
     * @param json
     * @param typeReference
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T parseObject(String json, TypeReference<T> typeReference) {
        if (StringUtils.isBlank(json) || typeReference == null) {
            return null;
        }

        try {
            return (T) (typeReference.getType().equals(String.class) ? json : jackson().readValue(json, typeReference));
        } catch (Exception e) {
            log.warn("json To obj is error", e);
            return null;
        }
    }

    public static String tryToString(ObjectMapper jackson, Object object) {
        if (object == null) {
            return null;
        }
        try {
            return jackson.writeValueAsString(object);
        } catch (Exception e) {
            log.error("Failed to serialize json object {} reason {}", object.getClass(), e);
        }
        try {
            ObjectMapper fieldAccessable = jacksonWithFieldAccessable();
            return fieldAccessable.writeValueAsString(object);
        } catch (Exception e) {
        }
        return String.valueOf(object);
    }

    /**
     * json字符串转换成泛型list
     *
     * @param mapper
     * @param collectionClass
     * @param elementClasses
     * @return
     */
    public static JavaType getCollectionType(ObjectMapper mapper, Class<?> collectionClass, Class<?>... elementClasses) {
        return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }
}
